package com.hsp.learn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @Author Zan
 * @Create 2024/10/8 10:48
 * @ClassName: RadixSort
 * @Description : 基数排序
 */
public class RadixSort {
    public static void main(String[] args) {
//        int[] arr = {53, 3, 542, 748, 14, 214};
//        radixSort(arr);
//        System.out.println(Arrays.toString(arr));

        int[] arr = new int[8000000];
        for (int i = 0; i < 8000000; i++) {
            arr[i] = (int) (Math.random() * 8000000); // 生成[0, 80000)的数
        }

        Date date1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(date1);
        System.out.println("排序前的时间是=" + format);
        radixSort(arr);
        Date date2 = new Date();
        String format2 = simpleDateFormat.format(date2);
        System.out.println("排序后的时间是=" + format2);
    }

    // 基数排序
    public static void radixSort(int[] arr) {

        // 先得到数组中最大的数的位数
        int max = arr[0]; // 假设第一位最大
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i]) {
                max = arr[i];
            }
        }
        int maxLength = (max + "").length();

        // 定义一个二维数组，表示十个桶，每个桶就是一个一维数组
        // 为了防止在放入的时候，数据溢出，则每一个一维数组(桶)，大小都为arr.length
        // 因此，其实基数排序就是一个通过空间换时间的经典算法
        int[][] bucket = new int[10][arr.length];

        // 为了记录每个桶中，实际存放了多少个数据，我们定义一个一维数组来记录各个桶每次放入的数据
        // bucketElementCounts[0] 记录的就是 bucket[0] 桶里面放入的数据的个数
        int[] bucketElementCounts = new int[10];

        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            // 第一轮排序(针对每个元素的个位进行排序处理)，第一次是个位，第二次是10位，第三次是100位
            for (int j = 0; j < arr.length; j++) {
                // 取出每个元素的个数
                int digitOfElement = (arr[j] / n) % 10;
                // 放入到对应的桶中
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
                bucketElementCounts[digitOfElement]++;
            }
            // 按照这个桶的顺序(一维数组的下标依次取出数据，放入原来数组)
            int index = 0;
            // 遍历每一个桶，并将桶中的数据，放入到原数组
            for (int k = 0; k < bucketElementCounts.length; k++) { // 10个桶，10次循环
                // 如果桶中有数据，才放入原数组中
                if (bucketElementCounts[k] != 0) { // 说明有数据
                    // 循环该桶，进行遍历
                    for (int l = 0; l < bucketElementCounts[k]; l++) { // 每个桶里面的数据
                        // 放入arr
                        arr[index++] = bucket[k][l];
                    }
                }
                // 每一轮排序后，需要将bucket桶里的元素都置0
                bucketElementCounts[k] = 0;
            }
        }
    }
}
